bitkeeper revision 1.1159.218.1 (41e3bb84y5sV55DN1DoraDUQU096Qw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 11 Jan 2005 11:41:56 +0000 (11:41 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 11 Jan 2005 11:41:56 +0000 (11:41 +0000)
More privileged-instruction emulation. We now handle CLTS and MOV
to/from CRn.

xen/arch/x86/memory.c
xen/arch/x86/traps.c
xen/include/asm-x86/mm.h
xen/include/asm-x86/processor.h

index f1982eb6c09b0d64cf99b121ca64aa5772f0220e..d53ee4c107a86bc422f32b0daae00f1e41b7f75e 100644 (file)
@@ -937,12 +937,41 @@ int get_page_type(struct pfn_info *page, u32 type)
 }
 
 
+int new_guest_cr3(unsigned long pfn)
+{
+    struct exec_domain *ed = current;
+    struct domain *d = ed->domain;
+    int okay, cpu = smp_processor_id();
+    unsigned long old_base_pfn;
+    
+    okay = get_page_and_type_from_pagenr(pfn, PGT_l2_page_table, d);
+    if ( likely(okay) )
+    {
+        invalidate_shadow_ldt(ed);
+
+        percpu_info[cpu].deferred_ops &= ~DOP_FLUSH_TLB;
+        old_base_pfn = pagetable_val(ed->mm.pagetable) >> PAGE_SHIFT;
+        ed->mm.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
+
+        shadow_mk_pagetable(&ed->mm);
+
+        write_ptbase(&ed->mm);
+
+        put_page_and_type(&frame_table[old_base_pfn]);
+    }
+    else
+    {
+        MEM_LOG("Error while installing new baseptr %08lx", ptr);
+    }
+
+    return okay;
+}
+
 static int do_extended_command(unsigned long ptr, unsigned long val)
 {
     int okay = 1, cpu = smp_processor_id();
     unsigned int cmd = val & MMUEXT_CMD_MASK;
     unsigned long pfn = ptr >> PAGE_SHIFT;
-    unsigned long old_base_pfn;
     struct pfn_info *page = &frame_table[pfn];
     struct exec_domain *ed = current;
     struct domain *d = ed->domain, *nd, *e;
@@ -1003,25 +1032,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
         break;
 
     case MMUEXT_NEW_BASEPTR:
-        okay = get_page_and_type_from_pagenr(pfn, PGT_l2_page_table, d);
-        if ( likely(okay) )
-        {
-            invalidate_shadow_ldt(ed);
-
-            percpu_info[cpu].deferred_ops &= ~DOP_FLUSH_TLB;
-            old_base_pfn = pagetable_val(ed->mm.pagetable) >> PAGE_SHIFT;
-            ed->mm.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
-
-            shadow_mk_pagetable(&ed->mm);
-
-            write_ptbase(&ed->mm);
-
-            put_page_and_type(&frame_table[old_base_pfn]);
-        }
-        else
-        {
-            MEM_LOG("Error while installing new baseptr %08lx", ptr);
-        }
+        okay = new_guest_cr3(pfn);
         break;
         
     case MMUEXT_TLB_FLUSH:
index fed80f1f7ef36ba5d065d35fb117b49c5abf1152..61f8b8b90aa03962249ffdf4ee99bba3d9e1f466 100644 (file)
@@ -383,14 +383,30 @@ asmlinkage void do_machine_check(struct xen_regs *regs)
     fatal_trap(TRAP_machine_check, regs);
 }
 
-asmlinkage int do_page_fault(struct xen_regs *regs)
+static inline void propagate_page_fault(unsigned long addr, u16 error_code)
 {
     trap_info_t *ti;
+    struct exec_domain *ed = current;
+    struct trap_bounce *tb = &ed->thread.trap_bounce;
+
+    ti = ed->thread.traps + 14;
+    tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE | TBF_EXCEPTION_CR2;
+    tb->cr2        = addr;
+    tb->error_code = error_code;
+    tb->cs         = ti->cs;
+    tb->eip        = ti->address;
+    if ( TI_GET_IF(ti) )
+        ed->vcpu_info->evtchn_upcall_mask = 1;
+
+    ed->mm.guest_cr2 = addr;
+}
+
+asmlinkage int do_page_fault(struct xen_regs *regs)
+{
     unsigned long off, addr, fixup;
     struct exec_domain *ed = current;
     struct domain *d = ed->domain;
     extern int map_ldt_shadow_page(unsigned int);
-    struct trap_bounce *tb = &ed->thread.trap_bounce;
     int cpu = ed->processor;
     int ret;
 
@@ -447,14 +463,7 @@ asmlinkage int do_page_fault(struct xen_regs *regs)
     if ( !GUEST_FAULT(regs) )
         goto xen_fault;
 
-    ti = ed->thread.traps + 14;
-    tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE | TBF_EXCEPTION_CR2;
-    tb->cr2        = addr;
-    tb->error_code = regs->error_code;
-    tb->cs         = ti->cs;
-    tb->eip        = ti->address;
-    if ( TI_GET_IF(ti) )
-        ed->vcpu_info->evtchn_upcall_mask = 1;
+    propagate_page_fault(addr, regs->error_code);
     return 0; 
 
  xen_fault:
@@ -497,45 +506,126 @@ asmlinkage int do_page_fault(struct xen_regs *regs)
 
 static int emulate_privileged_op(struct xen_regs *regs)
 {
-    u16 opcode;
+    extern long do_fpu_taskswitch(void);
+    extern void *decode_reg(struct xen_regs *regs, u8 b);
 
-    if ( get_user(opcode, (u16 *)regs->eip) || ((opcode & 0xff) != 0x0f) )
-        return 0;
+    struct exec_domain *ed = current;
+    unsigned long *reg, eip = regs->eip;
+    u8 opcode;
+
+    if ( get_user(opcode, (u8 *)eip) )
+        goto page_fault;
+    eip += 1;
+    if ( (opcode & 0xff) != 0x0f )
+        goto fail;
 
-    switch ( opcode >> 8 )
+    if ( get_user(opcode, (u8 *)eip) )
+        goto page_fault;
+    eip += 1;
+
+    switch ( opcode )
     {
+    case 0x06: /* CLTS */
+        (void)do_fpu_taskswitch();
+        break;
+
     case 0x09: /* WBINVD */
-        if ( !IS_CAPABLE_PHYSDEV(current->domain) )
+        if ( !IS_CAPABLE_PHYSDEV(ed->domain) )
         {
             DPRINTK("Non-physdev domain attempted WBINVD.\n");
-            return 0;
+            goto fail;
         }
         wbinvd();
-        regs->eip += 2;
-        return 1;
-        
+        break;
+
+    case 0x20: /* MOV CR?,<reg> */
+        if ( get_user(opcode, (u8 *)eip) )
+            goto page_fault;
+        eip += 1;
+        if ( (opcode & 0xc0) != 0xc0 )
+            goto fail;
+        reg = decode_reg(regs, opcode);
+        switch ( (opcode >> 3) & 7 )
+        {
+        case 0: /* Read CR0 */
+            *reg = 
+                (read_cr0() & ~X86_CR0_TS) | 
+                (test_bit(EDF_GUEST_STTS, &ed->ed_flags) ? X86_CR0_TS : 0);
+            break;
+
+        case 2: /* Read CR2 */
+            *reg = ed->mm.guest_cr2;
+            break;
+            
+        case 3: /* Read CR3 */
+            *reg = pagetable_val(ed->mm.pagetable);
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    case 0x22: /* MOV <reg>,CR? */
+        if ( get_user(opcode, (u8 *)eip) )
+            goto page_fault;
+        eip += 1;
+        if ( (opcode & 0xc0) != 0xc0 )
+            goto fail;
+        reg = decode_reg(regs, opcode);
+        switch ( (opcode >> 3) & 7 )
+        {
+        case 0: /* Write CR0 */
+            if ( *reg & X86_CR0_TS ) /* XXX ignore all but TS bit */
+                (void)do_fpu_taskswitch;
+            break;
+
+        case 2: /* Write CR2 */
+            ed->mm.guest_cr2 = *reg;
+            break;
+            
+        case 3: /* Write CR3 */
+            LOCK_BIGLOCK(ed->domain);
+            (void)new_guest_cr3(*reg);
+            UNLOCK_BIGLOCK(ed->domain);
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
     case 0x30: /* WRMSR */
-        if ( !IS_PRIV(current->domain) )
+        if ( !IS_PRIV(ed->domain) )
         {
             DPRINTK("Non-priv domain attempted WRMSR.\n");
-            return 0;
+            goto fail;
         }
         wrmsr(regs->ecx, regs->eax, regs->edx);
-        regs->eip += 2;
-        return 1;
+        break;
 
     case 0x32: /* RDMSR */
-        if ( !IS_PRIV(current->domain) )
+        if ( !IS_PRIV(ed->domain) )
         {
             DPRINTK("Non-priv domain attempted RDMSR.\n");
-            return 0;
+            goto fail;
         }
         rdmsr(regs->ecx, regs->eax, regs->edx);
-        regs->eip += 2;
-        return 1;
+        break;
+
+    default:
+        goto fail;
     }
 
+    regs->eip = eip;
+    return EXCRET_fault_fixed;
+
+ fail:
     return 0;
+
+ page_fault:
+    propagate_page_fault(eip, 0);
+    return EXCRET_fault_fixed;
 }
 
 asmlinkage int do_general_protection(struct xen_regs *regs)
index af2abb5a0aaa7740c18ec90e66e90535e560fe9c..05712d80c3e938b82fb5f7157fb2cffcdac9032d 100644 (file)
@@ -278,6 +278,8 @@ extern ptwr_info_t ptwr_info[];
 void ptwr_flush(const int);
 int ptwr_do_page_fault(unsigned long);
 
+int new_guest_cr3(unsigned long pfn);
+
 #define __cleanup_writable_pagetable(_what)                                 \
 do {                                                                        \
     int cpu = smp_processor_id();                                           \
index bed1464bac8eedd2dfe2287ba60364aa1fe1e11c..9c66c86ae7c0a5184cba31a3e452330f2a081075 100644 (file)
@@ -485,6 +485,9 @@ struct mm_struct {
     unsigned long min_pfn;             /* min host physical */
     unsigned long max_pfn;             /* max host physical */
 
+    /* Virtual CR2 value. Can be read/written by guest. */
+    unsigned long guest_cr2;
+
     /* shadow mode status and controls */
     unsigned int shadow_mode;  /* flags to control shadow table operation */
     pagetable_t  shadow_table;